package com.tsfyun.scm.service.impl.customer;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.RandomUtil;
import com.baidu.aip.ocr.AipOcr;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.base.Stopwatch;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.tsfyun.common.base.config.properties.BaiduProperties;
import com.tsfyun.common.base.config.properties.DDRemindProperties;
import com.tsfyun.common.base.config.OrikaBeanMapper;
import com.tsfyun.common.base.constant.LoginConstant;
import com.tsfyun.common.base.dto.*;
import com.tsfyun.common.base.enums.LoginRoleTypeEnum;
import com.tsfyun.common.base.enums.MessageNodeEnum;
import com.tsfyun.common.base.enums.ResultCodeEnum;
import com.tsfyun.common.base.enums.WxMessageDefineTemplate;
import com.tsfyun.common.base.enums.domain.CustomerStatusEnum;
import com.tsfyun.common.base.enums.domain.DomainOprationEnum;
import com.tsfyun.common.base.enums.domain.DomainTypeEnum;
import com.tsfyun.common.base.exception.ServiceException;
import com.tsfyun.common.base.help.DingTalkNoticeUtil;
import com.tsfyun.common.base.help.excel.ExcelUtil;
import com.tsfyun.common.base.security.LoginVO;
import com.tsfyun.common.base.security.SecurityUtil;
import com.tsfyun.common.base.util.*;
import com.tsfyun.common.base.validator.ValidatorUtils;
import com.tsfyun.common.base.vo.CustomerSimpleVO;
import com.tsfyun.common.base.vo.QichachaCompanyVO;
import com.tsfyun.common.base.vo.SimpleBusinessVO;
import com.tsfyun.scm.client.ToolClient;
import com.tsfyun.scm.config.redis.RedisUtils;
import com.tsfyun.scm.dto.customer.*;
import com.tsfyun.scm.dto.support.TaskNoticeContentDTO;
import com.tsfyun.scm.entity.customer.Customer;
import com.tsfyun.scm.entity.customer.CustomerAbroadDeliveryInfo;
import com.tsfyun.scm.entity.customer.CustomerBank;
import com.tsfyun.scm.entity.customer.CustomerDeliveryInfo;
import com.tsfyun.scm.entity.file.UploadFile;
import com.tsfyun.scm.entity.user.LogLogin;
import com.tsfyun.scm.entity.user.Person;
import com.tsfyun.scm.excel.CustomerExcel;
import com.tsfyun.scm.mapper.customer.CustomerMapper;
import com.tsfyun.scm.security.config.StringRedisUtils;
import com.tsfyun.scm.service.common.ICommonService;
import com.tsfyun.scm.service.customer.*;
import com.tsfyun.common.base.extension.ServiceImpl;
import com.tsfyun.scm.service.file.IUploadFileService;
import com.tsfyun.scm.service.finance.IReceiptAccountService;
import com.tsfyun.scm.service.finance.ITransactionFlowService;
import com.tsfyun.scm.service.order.IImpOrderCostService;
import com.tsfyun.scm.service.support.ITaskNoticeContentService;
import com.tsfyun.scm.service.system.IStatusHistoryService;
import com.tsfyun.scm.service.third.IShortMessageService;
import com.tsfyun.scm.service.third.IWxMessageService;
import com.tsfyun.scm.service.user.ICustomerPersonService;
import com.tsfyun.scm.service.user.ILogLoginService;
import com.tsfyun.scm.service.user.ILoginService;
import com.tsfyun.scm.service.user.IPersonService;
import com.tsfyun.scm.util.CompanyUtil;
import com.tsfyun.scm.util.TsfWeekendSqls;
import com.tsfyun.scm.vo.base.ClientFileVO;
import com.tsfyun.scm.vo.customer.*;
import com.tsfyun.scm.vo.customer.client.CheckCompanyResultVO;
import com.tsfyun.scm.vo.customer.client.ClientCustomerGradeVO;
import com.tsfyun.scm.vo.customer.client.ClientFinanceInfoVO;
import com.tsfyun.scm.vo.user.CustomerLoginInfoVO;
import com.tsfyun.scm.vo.user.SimplePersonInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.map.LinkedMap;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.weekend.WeekendSqls;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 *
 * @since 2020-03-03
 */
@RefreshScope
@Slf4j
@Service
public class CustomerServiceImpl extends ServiceImpl<Customer> implements ICustomerService {

    @Autowired
    private OrikaBeanMapper beanMapper;
    @Autowired
    private CustomerMapper customerMapper;
    @Autowired
    private IUploadFileService uploadFileService;
    @Autowired
    private IPersonService personService;
    @Autowired
    private ICustomerDeliveryInfoService customerDeliveryInfoService;
    @Autowired
    private ICustomerAbroadDeliveryInfoService customerAbroadDeliveryInfoService;
    @Autowired
    private ICustomerPersonChangeService customerPersonChangeService;
    @Autowired
    private ISupplierService supplierService;
    @Value("${upload.excel.maxmum:500}")
    private int uploadMaxmum;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private IStatusHistoryService statusHistoryService;
    @Autowired
    private ITaskNoticeContentService taskNoticeContentService;
    @Autowired
    private ITransactionFlowService transactionFlowService;
    @Autowired
    private IReceiptAccountService receiptAccountService;
    @Autowired
    private IImpOrderCostService impOrderCostService;
    @Autowired
    private ILogLoginService logLoginService;
    @Autowired
    private BaiduProperties baiduProperties;
    @Resource
    private ToolClient toolClient;
    @Autowired
    private ICommonService commonService;
    @Resource
    private DDRemindProperties ddRemindProperties;
    @Autowired
    private IWxMessageService wxMessageService;
    @Autowired
    private ILoginService loginService;
    @Autowired
    private IShortMessageService shortMessageService;
    @Value("${spring.profiles.active:dev}")
    private String profiles;
    @Autowired
    private ICustomerPersonService customerPersonService;
    @Autowired
    private StringRedisUtils stringRedisUtils;
    @Autowired
    private ICustomerBankService customerBankService;


    @Override
    public PageInfo<Customer> selectPageList(CustomerQTO qto) {
        PageHelper.startPage(qto.getPage(), qto.getLimit());
        Map<String, Object> params = beanMapper.map(qto, Map.class);
        List<Customer> customers = customerMapper.simpleSelect(params);
        return new PageInfo<>(customers);
    }

    @Override
    public PageInfo<CustomerVO> pageList(CustomerQTO qto) {
        PageHelper.startPage(qto.getPage(), qto.getLimit());
        PageInfo<CustomerVO> pageInfo = new PageInfo();
        Map<String, Object> params = beanMapper.map(qto, Map.class);
        List<CustomerVO> customerVOS = customerMapper.customerAndUserList(params);
        if (CollectionUtil.isNotEmpty(customerVOS)) {
            //此处需注意，分页的这个list必须是当前的查询返回的那个集合，不能是转换之后的，否则分页无效
            pageInfo = new PageInfo<>(customerVOS);
            //查询商务名称和销售名称，不在SQL中做级联关联查询
            Set<Long> personSet = Sets.newHashSet(customerVOS.stream().map(CustomerVO::getSalePersonId).collect(Collectors.toSet()));
            personSet.addAll(customerVOS.stream().map(CustomerVO::getBusPersonId).collect(Collectors.toSet()));
            personSet.addAll(customerVOS.stream().map(CustomerVO::getBusSecPersonId).collect(Collectors.toSet()));
            Map<Long, SimplePersonInfo> personMap = personService.findByIds(personSet);
            // 获取所有客户登录信息
            Map<Long, CustomerLoginInfoVO> loginInfoVOMap = loginService.allCustomerLoginInfo();
            customerVOS.stream().forEach(r -> {
                if (CollectionUtil.isNotEmpty(personMap)) {
                    SimplePersonInfo simpleSalePersonInfo = personMap.get(r.getSalePersonId());
                    SimplePersonInfo simpleBusPersonInfo = personMap.get(r.getBusPersonId());
                    SimplePersonInfo simpleBusSecPersonInfo = personMap.get(r.getBusSecPersonId());
                    r.setSalePersonName(Objects.nonNull(simpleSalePersonInfo) ? simpleSalePersonInfo.getName() : null);
                    r.setBusPersonName(Objects.nonNull(simpleBusPersonInfo) ? simpleBusPersonInfo.getName() : null);
                    r.setBusSecPersonName(Objects.nonNull(simpleBusSecPersonInfo) ? simpleBusSecPersonInfo.getName() : null);
                }
                r.setIsPhone(Boolean.FALSE);
                r.setIsWechat(Boolean.FALSE);
                CustomerLoginInfoVO loginInfoVO = loginInfoVOMap.get(r.getId());
                if(Objects.nonNull(loginInfoVO)){
                    r.setPhoneNo(loginInfoVO.getPhoneNo());
                    r.setIsPhone(loginInfoVO.getIsPhone());
                    r.setIsWechat(loginInfoVO.getIsWechat());
                }
            });
        }
        return pageInfo;
    }

    @Override
    public CustomerVO detail(Long id) {
        Customer customer = super.getById(id);
        TsfPreconditions.checkArgument(Objects.nonNull(customer), new ServiceException("客户信息不存在"));
        CustomerVO customerVO = beanMapper.map(customer, CustomerVO.class);
        //获取商务和销售人员名称
        Set<Long> personSet = Sets.newHashSet(customer.getBusPersonId(), customer.getSalePersonId());
        Map<Long, SimplePersonInfo> personMap = personService.findByIds(personSet);
        if (CollectionUtil.isNotEmpty(personMap)) {
            SimplePersonInfo simpleSalePersonInfo = personMap.get(customer.getSalePersonId());
            SimplePersonInfo simpleBusPersonInfo = personMap.get(customer.getBusPersonId());
            customerVO.setSalePersonName(Objects.nonNull(simpleSalePersonInfo) ? simpleSalePersonInfo.getName() : null);
            customerVO.setBusPersonName(Objects.nonNull(simpleBusPersonInfo) ? simpleBusPersonInfo.getName() : null);
        }
        return customerVO;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long addPlus(CustomerPlusInfoDTO dto) {
        // 添加客户主要信息
        Customer customer = addCustomer(dto.getCustomer());
        // 保存收货信息
        customerDeliveryInfoService.saveList(customer.getId(), dto.getDeliverys());
        // 保存境外收货信息
        customerAbroadDeliveryInfoService.saveList(customer.getId(), dto.getAbroadDeliverys());
        // 保存客户银行信息
        customerBankService.saveList(customer.getId(),dto.getBanks());
        //关联文件信息
        uploadFileService.relateFile(customer.getId().toString(), dto.getFile());
        // 提交审核
        if(Objects.equals(dto.getCustomer().getIsSubmit(),Boolean.TRUE)){
            customer.setStatusId(CustomerStatusEnum.TYPE_1.getCode());
            super.updateByIdSelective(customer);

            TaskNoticeContentDTO taskNoticeContentDTO = new TaskNoticeContentDTO();
            taskNoticeContentDTO.setDocumentType(DomainTypeEnum.CUSTOMER.getCode());
            taskNoticeContentDTO.setDocumentId(customer.getId().toString());
            taskNoticeContentDTO.setCustomerId(customer.getId());
            taskNoticeContentDTO.setOperationCode(DomainOprationEnum.CUSTOMER_APPROVE.getCode());
            taskNoticeContentDTO.setContent(String.format("客户【%s】已完善资料需要您审核，请立即处理。",customer.getName()));
            Map<String,Object> queryParamsMap = new LinkedHashMap<String,Object>(){{
                put("statusId",CustomerStatusEnum.TYPE_1.getCode());
            }};
            queryParamsMap.put("name",customer.getName());
            taskNoticeContentDTO.setQueryParamsMap(queryParamsMap);
            taskNoticeContentDTO.setIsExeRemove(Boolean.TRUE);
            taskNoticeContentService.add(taskNoticeContentDTO);
        }
        // 记录状态
        CustomerStatusEnum nowCustomerStatus = CustomerStatusEnum.of(customer.getStatusId());
        statusHistoryService.saveHistory(DomainOprationEnum.CUSTOMER_ADD,
                customer.getId().toString(),Customer.class.getName(),
                nowCustomerStatus.getCode(),nowCustomerStatus.getName(),"后台备案客户");
        return customer.getId();
    }

    //单独添加客户
    @Transactional(rollbackFor = Exception.class)
    public Customer addCustomer(CustomerDTO dto) {
        Customer customer = beanMapper.map(dto, Customer.class);
        //未填写客户编码随机生成
        if (StringUtils.isEmpty(customer.getCode())) {
            for (int i = 0; i < 10; i++) {
                String code = RandomUtil.randomNumbers(6);
                Customer condition = new Customer();
                condition.setCode("XDT-"+code);
                if (super.count(condition) == 0) {
                    customer.setCode(condition.getCode());
                    break;
                }
            }
            TsfPreconditions.checkArgument(StringUtils.isNotEmpty(customer.getCode()), new ServiceException("程序繁忙请稍后重试"));
        }
        //去除特殊符号
        customer.setName(StringUtils.removeSpecialSymbol(customer.getName()).replace("(", "（").replace(")", "）"));
        //拼音处理
        customer.setPinyin(ChineseToPingYin.getPingYin(customer.getName()));

        //销售人员
        Person salePerson = null;
        if (Objects.nonNull(customer.getSalePersonId())) {
            salePerson = personService.getById(customer.getSalePersonId());
            TsfPreconditions.checkArgument(Objects.nonNull(salePerson), new ServiceException("您选择的销售人员不存在"));
            //写入认领日期
            customer.setClaimDate(LocalDateTimeUtils.convertLocalDate());
            customer.setSalePersonId(salePerson.getId());
        }
        // 主要商务
        Person busPerson = null;
        if (Objects.nonNull(customer.getBusPersonId())) {
            busPerson = personService.getById(dto.getBusPersonId());
            TsfPreconditions.checkArgument(Objects.nonNull(busPerson), new ServiceException("您选择的主要商务人员不存在"));
            customer.setBusPersonId(busPerson.getId());
        }
        // 辅助商务
        Person busSecPerson = null;
        if (Objects.nonNull(customer.getBusSecPersonId())) {
            busSecPerson = personService.getById(dto.getBusSecPersonId());
            TsfPreconditions.checkArgument(Objects.nonNull(busSecPerson), new ServiceException("您选择的辅助商务人员不存在"));
            customer.setBusSecPersonId(busSecPerson.getId());
            TsfPreconditions.checkArgument(Objects.nonNull(busPerson), new ServiceException("选择了辅助商务人员,主要商务人员必须选择"));
        }
        //设置客户默认状态
        customer.setStatusId(CustomerStatusEnum.TYPE_0.getCode());
        try {
            customer.setAddress(StringUtils.removeSpecialSymbol(customer.getAddress()));
            customer.setAddressEn(StringUtils.removeSpecialSymbol(customer.getAddressEn()));
            customer.setNameEn(StringUtils.removeSpecialSymbol(customer.getNameEn()));
            customer.setLinkPerson(StringUtils.removeSpecialSymbol(customer.getLinkPerson()));
            customer.setLinkAddress(StringUtils.removeSpecialSymbol(customer.getLinkAddress()));
            customer.setLinkTel(StringUtils.removeSpecialSymbol(customer.getLinkTel()));
            customer.setInvoiceBankName(StringUtils.removeSpecialSymbol(customer.getInvoiceBankName()));
            customer.setInvoiceBankAccount(StringUtils.removeSpecialSymbol(customer.getInvoiceBankAccount()));
            customer.setInvoiceBankAddress(StringUtils.removeSpecialSymbol(customer.getInvoiceBankAddress()));
            customer.setInvoiceBankTel(StringUtils.removeSpecialSymbol(customer.getInvoiceBankTel()));
            customer.setDisabled(Boolean.FALSE);
            super.saveNonNull(customer);
            if (Objects.nonNull(salePerson)) {
                //记录销售人员变更
                customerPersonChangeService.saveSaleChange(customer.getId(), null, salePerson, "首次新增客户");
            }
            if (Objects.nonNull(busPerson)) {
                //记录商务人员变更
                customerPersonChangeService.saveBusChange(customer.getId(), null, busPerson, "首次新增客户");
            }
        } catch (DuplicateKeyException e) {
            if (e.getMessage().contains("UK_customer_code")) {
                throw new ServiceException("客户代码已经存在请修改");
            } else if (e.getMessage().contains("UK_customer_name")) {
                throw new ServiceException("客户名称已经存在");
            } else {
                throw new ServiceException("保存失败，请检查数据是否填写正确");
            }
        }
        return customer;
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void editPlus(CustomerPlusInfoDTO dto) {
        Customer customer = editCustomer(dto.getCustomer());
        customerDeliveryInfoService.saveList(customer.getId(), dto.getDeliverys());
        customerAbroadDeliveryInfoService.saveList(customer.getId(), dto.getAbroadDeliverys());
        customerBankService.saveList(customer.getId(),dto.getBanks());
    }

    //单独修改客户信息
    @Transactional(rollbackFor = Exception.class)
    public Customer editCustomer(CustomerDTO dto) {
        TsfPreconditions.checkArgument(!Objects.equals(Long.valueOf(0), dto.getId()), new ServiceException("未知客户禁止修改"));
        Customer oldCustomer = super.getById(dto.getId());
        TsfPreconditions.checkArgument(Objects.nonNull(oldCustomer), new ServiceException("客户信息不存在"));
        //已审核就不允许修改（客户端）
        String roleType = SecurityUtil.getCurrent().getRoleType();
        if(Objects.equals(roleType, LoginRoleTypeEnum.CLIENT.getCode())) {
            TsfPreconditions.checkArgument(!Objects.equals(oldCustomer.getStatusId(),CustomerStatusEnum.TYPE_2.getCode()),new ServiceException("客户已审核通过，不允许修改"));
        }

        Customer update = beanMapper.map(oldCustomer, Customer.class);
        //单个赋值防止客户端未提交数据清除
        update.setCode(dto.getCode());
        //如果置空客户编码则再次生成
        //未填写客户编码随机生成
        if (StringUtils.isEmpty(update.getCode())) {
            update.setCode(createCustomerCode());
        }
        update.setName(StringUtils.removeSpecialSymbol(dto.getName()).replace("(", "（").replace(")", "）"));
        update.setPinyin(ChineseToPingYin.getPingYin(update.getName()));
        update.setNameEn(dto.getNameEn());
        update.setSocialNo(dto.getSocialNo());
        update.setCustomsCode(dto.getCustomsCode());
        update.setCiqNo(dto.getCiqNo());
        update.setLegalPerson(dto.getLegalPerson());
        update.setTel(dto.getTel());
        update.setFax(dto.getFax());
        update.setAddress(dto.getAddress());
        update.setAddressEn(dto.getAddressEn());
        update.setTaxpayerNo(dto.getTaxpayerNo());
        update.setInvoiceBankName(dto.getInvoiceBankName());
        update.setInvoiceBankAccount(dto.getInvoiceBankAccount());
        update.setLinkPerson(dto.getLinkPerson());
        update.setLinkTel(dto.getLinkTel());
        CustomerStatusEnum oldStatus = CustomerStatusEnum.of(oldCustomer.getStatusId());
        // 待审核
        if(Objects.equals(dto.getIsSubmit(),Boolean.TRUE) && Objects.equals(oldStatus,CustomerStatusEnum.TYPE_0)){
            update.setStatusId(CustomerStatusEnum.TYPE_1.getCode());

            TaskNoticeContentDTO taskNoticeContentDTO = new TaskNoticeContentDTO();
            taskNoticeContentDTO.setDocumentType(DomainTypeEnum.CUSTOMER.getCode());
            taskNoticeContentDTO.setDocumentId(update.getId().toString());
            taskNoticeContentDTO.setCustomerId(update.getId());
            taskNoticeContentDTO.setOperationCode(DomainOprationEnum.CUSTOMER_APPROVE.getCode());
            taskNoticeContentDTO.setContent(String.format("客户【%s】已完善资料需要您审核，请立即处理。",update.getName()));
            Map<String,Object> queryParamsMap = new LinkedHashMap<String,Object>(){{
                put("statusId",CustomerStatusEnum.TYPE_1.getCode());
            }};
            queryParamsMap.put("name",update.getName());
            taskNoticeContentDTO.setQueryParamsMap(queryParamsMap);
            taskNoticeContentDTO.setIsExeRemove(Boolean.TRUE);
            taskNoticeContentService.add(taskNoticeContentDTO);
        }
        // 联系地址
        update.setLinkAddress(String.format("%s %s %s %s",
                StringUtils.removeSpecialSymbol(dto.getInvoiceProvince()),
                StringUtils.removeSpecialSymbol(dto.getInvoiceCity()),
                StringUtils.removeSpecialSymbol(dto.getInvoiceArea()),
                StringUtils.removeSpecialSymbol(dto.getLinkAddress())));
        update.setInvoiceMemo(dto.getInvoiceMemo());
        update.setInvoiceBankAddress(dto.getInvoiceBankAddress());
        update.setInvoiceBankTel(dto.getInvoiceBankTel());
        update.setSalePersonId(dto.getSalePersonId());
        update.setBusPersonId(dto.getBusPersonId());
        update.setBusSecPersonId(dto.getBusSecPersonId());
        if(Objects.nonNull(update.getBusSecPersonId()) && Objects.isNull(update.getBusPersonId())){
            throw new ServiceException("选择了辅助商务人员,主要商务人员必须选择");
        }
        //销售人员发生变更
        if (!Objects.equals(oldCustomer.getSalePersonId(), update.getSalePersonId())) {
            Person oldSalePerson = (oldCustomer.getSalePersonId() != null) ? personService.getById(oldCustomer.getSalePersonId()) : null;
            Person nowSalePerson = (update.getSalePersonId() != null) ? personService.getById(update.getSalePersonId()) : null;
            //销售人员有变更也更改认领日期
            update.setClaimDate(LocalDateTimeUtils.convertLocalDate());
            //记录销售人员变更
            customerPersonChangeService.saveSaleChange(update.getId(), oldSalePerson, nowSalePerson, "修改客户变更");
        }
        //商务人员发生变更
        if (!Objects.equals(oldCustomer.getBusPersonId(), update.getBusPersonId())) {
            Person oldBusPerson = (oldCustomer.getBusPersonId() != null) ? personService.getById(oldCustomer.getBusPersonId()) : null;
            Person nowBusPerson = (update.getBusPersonId() != null) ? personService.getById(update.getBusPersonId()) : null;
            //记录商务人员变更
            customerPersonChangeService.saveBusChange(update.getId(), oldBusPerson, nowBusPerson, "修改客户变更");
        }
        try {
            CustomerStatusEnum nowStatus = CustomerStatusEnum.of(update.getStatusId());
            statusHistoryService.saveHistory(DomainOprationEnum.CUSTOMER_EDIT,
                    update.getId().toString(),Customer.class.getName(),
                    oldStatus.getCode(),oldStatus.getName(),
                    nowStatus.getCode(),nowStatus.getName(),
                    "修改客户");
            // 刷新用户登录的客户数据
            refreshCacheCompany(update);
            super.updateById(update);
        } catch (DuplicateKeyException e) {
            if (e.getMessage().contains("UK_customer_code")) {
                throw new ServiceException("客户代码已经存在请修改");
            } else if (e.getMessage().contains("UK_customer_name")) {
                throw new ServiceException("客户名称已经存在");
            } else {
                throw new ServiceException("保存失败，请检查数据是否填写正确");
            }
        }
        return update;
    }

    /**
     * 生成客户编号
     *
     * @return
     */
    public String createCustomerCode() {
        String code = "";
        for (int i = 0; i < 10; i++) {
            code = "XDT-"+RandomUtil.randomNumbers(6);
            Customer condition = new Customer();
            condition.setCode(code);
            if (super.count(condition) == 0) {
                break;
            }
        }
        TsfPreconditions.checkArgument(StringUtils.isNotEmpty(code), new ServiceException("系统繁忙请稍后重试"));
        return code;
    }

    @Override
    public CustomerPlusVO detailPlus(Long id) {
        Customer customer = super.getById(id);
        TsfPreconditions.checkArgument(Objects.nonNull(customer), new ServiceException("客户信息不存在"));
        CustomerPlusVO customerPlusVO = new CustomerPlusVO();
        CustomerVO customerVO = beanMapper.map(customer, CustomerVO.class);
        String[] address = StringUtils.removeSpecialSymbol(customerVO.getLinkAddress()).split(" ");
        if(address.length>=3){
            customerVO.setInvoiceProvince(address[0]);
            customerVO.setInvoiceCity(address[1]);
            customerVO.setInvoiceArea(address[2]);
            address[0]="";
            address[1]="";
            address[2]="";
            customerVO.setLinkAddress(String.join("",address));
        }
        //获取商务和销售人员名称
        Set<Long> personSet = Sets.newHashSet(customer.getBusPersonId(), customer.getSalePersonId());
        Map<Long, SimplePersonInfo> personMap = personService.findByIds(personSet);
        if (CollectionUtil.isNotEmpty(personMap)) {
            SimplePersonInfo simpleSalePersonInfo = personMap.get(customer.getSalePersonId());
            SimplePersonInfo simpleBusPersonInfo = personMap.get(customer.getBusPersonId());
            customerVO.setSalePersonName(Objects.nonNull(simpleSalePersonInfo) ? simpleSalePersonInfo.getName() : null);
            customerVO.setBusPersonName(Objects.nonNull(simpleBusPersonInfo) ? simpleBusPersonInfo.getName() : null);
        }

        customerPlusVO.setCustomer(customerVO);
        List<CustomerDeliveryInfo> customerDeliveryInfos = customerDeliveryInfoService.list(id);
        if (CollectionUtil.isNotEmpty(customerDeliveryInfos)) {
            //先按是否默认排序，然后再按修改日期排序
            customerDeliveryInfos = customerDeliveryInfos.stream().sorted(Comparator.comparing(CustomerDeliveryInfo::getIsDefault).thenComparing(CustomerDeliveryInfo::getDateUpdated).reversed())
                    .collect(Collectors.toList());
            List<CustomerDeliveryInfoVO> customerDeliveryInfoVOS = beanMapper.mapAsList(customerDeliveryInfos, CustomerDeliveryInfoVO.class);
            customerPlusVO.setDeliverys(customerDeliveryInfoVOS);
        }

        List<CustomerAbroadDeliveryInfo> customerAbroadDeliveryInfos = customerAbroadDeliveryInfoService.list(id);
        if (CollectionUtil.isNotEmpty(customerAbroadDeliveryInfos)) {
            //先按是否默认排序，然后再按修改日期排序
            customerAbroadDeliveryInfos = customerAbroadDeliveryInfos.stream().sorted(Comparator.comparing(CustomerAbroadDeliveryInfo::getIsDefault).thenComparing(CustomerAbroadDeliveryInfo::getDateUpdated).reversed())
                    .collect(Collectors.toList());
            List<CustomerAbroadDeliveryInfoVO> customerAbroadDeliveryInfoVOS = beanMapper.mapAsList(customerAbroadDeliveryInfos, CustomerAbroadDeliveryInfoVO.class);
            customerPlusVO.setAbroadDeliverys(customerAbroadDeliveryInfoVOS);
        }
        List<CustomerBank> customerBanks = customerBankService.list(id);
        if(CollectionUtil.isNotEmpty(customerBanks)) {
            //先按是否默认排序，然后再按修改日期排序
            customerBanks = customerBanks.stream().sorted(Comparator.comparing(CustomerBank::getIsDefault).thenComparing(CustomerBank::getDateUpdated).reversed())
                    .collect(Collectors.toList());
            List<CustomerBankVO> customerBankVOS = beanMapper.mapAsList(customerBanks, CustomerBankVO.class);
            customerPlusVO.setCustomerBanks(customerBankVOS);
        }
        return customerPlusVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateDisabled(Long id, Boolean disabled) {
        TsfPreconditions.checkArgument(!Objects.equals(Long.valueOf(0), id), new ServiceException("当前客户禁止修改"));
        Customer customer = super.getById(id);
        TsfPreconditions.checkArgument(Objects.nonNull(customer), new ServiceException("客户信息不存在"));
        Customer update = new Customer();
        update.setDisabled(disabled);
        customerMapper.updateByExampleSelective(update, Example.builder(Customer.class).where(
                WeekendSqls.<Customer>custom().andEqualTo(Customer::getId, id)
        ).build());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void remove(Long id) {
        TsfPreconditions.checkArgument(!Objects.equals(Long.valueOf(0), id), new ServiceException("当前客户禁止删除"));
        Customer customer = super.getById(id);
        TsfPreconditions.checkArgument(Objects.nonNull(customer), new ServiceException("客户信息不存在"));
        //检查是否存在关联业务数据，已经由外键解决
        //查看是否存在供应商信息，如果存在供应商信息不允许删除，以免误删
        int supplierCount = supplierService.countByCustomerId(id);
        TsfPreconditions.checkArgument(supplierCount < 1, new ServiceException(String.format("该客户下面存在%d条供应商信息，不允许删除", supplierCount)));
        int customerDeliveryCount = customerDeliveryInfoService.countByCustomerId(id);
        TsfPreconditions.checkArgument(customerDeliveryCount < 1, new ServiceException(String.format("该客户下面存在%d条收货信息，不允许删除", customerDeliveryCount)));
        try {
            super.removeById(id);
        } catch (DataIntegrityViolationException e) {
            throw new ServiceException("当前客户存在关联性数据，不允许删除");
        }
    }

    @Override
    public Customer findByName(String name) {
        if (StringUtils.isEmpty(name)) {
            //未知客户
            return super.getById(Long.valueOf(0));
        }
        return customerMapper.findByName(name);
    }

    @Override
    public Customer findByNameWithRight(String name) {
        TsfPreconditions.checkArgument(StringUtils.isNotEmpty(name), new ServiceException("客户不存在"));
        //判断登录用户是否有此客户权限
        Map<String, Object> params = Maps.newHashMap();
        params.put("name", name);
        Customer customerRight = customerMapper.getByNameWithRight(params);
        Optional.ofNullable(customerRight).orElseThrow(() -> new ServiceException("客户不存在或您无此客户权限"));
        //是否禁用
        TsfPreconditions.checkArgument(!customerRight.getDisabled(), new ServiceException("客户已被禁用"));
        return customerRight;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void importData(MultipartFile file) {
        Stopwatch stopwatch = Stopwatch.createStarted();
        List<CustomerExcel> dataList;
        try {
            dataList = ExcelUtil.readExcel(file, CustomerExcel.class, 1);
        } catch (Exception e) {
            log.error("读取导入的excel文件异常", e);
            throw new ServiceException("导入数据异常，请仔细检查您的导入文件是否符合模板要求");
        }
        if (CollectionUtils.isEmpty(dataList)) {
            throw new ServiceException("本次没有可以导入的数据");
        }
        TsfPreconditions.checkArgument(dataList.size() <= uploadMaxmum, new ServiceException(String.format("您本次导入的数据超过%d条的上限了", uploadMaxmum)));
        List<CustomerExcel> finalDataList = dataList;
        IntStream.range(0, dataList.size()).forEach(idx -> {
            CustomerExcel customerExcel = finalDataList.get(idx);
            int contentRowNo = idx + 1;
            ValidatorUtils.validateEntity(customerExcel, contentRowNo);
            CustomerDTO customerDTO = beanMapper.map(customerExcel, CustomerDTO.class);
            try {
                this.addCustomer(customerDTO);
            } catch (Exception e) {
                log.error(String.format("处理第%d行时发生异常", contentRowNo), e);
                if (e instanceof ServiceException) {
                    throw new ServiceException(String.format("第%d行%s", contentRowNo, e.getMessage()));
                }
                throw new ServiceException(String.format("系统在处理第%d行数据时发生异常，请仔细检查您导入的文件数据格式是否正确", contentRowNo));
            }
        });
        stopwatch.stop();
        log.info("本次成功导入{}条数据，耗时：{}秒", dataList.size(), stopwatch.elapsed(TimeUnit.SECONDS));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void changeCustomerSaleOrBus(ChangeCustomerPersonDTO dto) {
        Customer customer = super.getById(dto.getId());
        TsfPreconditions.checkArgument(Objects.nonNull(customer), new ServiceException("客户信息不存在"));
        if (Objects.nonNull(dto.getSalePersonId()) && Objects.nonNull(dto.getBusPersonId())) {
            throw new ServiceException("您不能同时变更客户的商务或者销售人员");
        }
        //变更销售
        if (Objects.nonNull(dto.getSalePersonId())) {
            TsfPreconditions.checkArgument(!Objects.equals(dto.getSalePersonId(), customer.getSalePersonId()), new ServiceException("您本次没有更改销售人员"));
            Person newSalePerson = personService.getById(dto.getSalePersonId());
            Optional.ofNullable(newSalePerson).orElseThrow(() -> new ServiceException("您选择的销售人员不存在"));
            //修改客户认领日期和最新销售人员
            Customer update = new Customer();
            update.setSalePersonId(newSalePerson.getId());
            update.setClaimDate(LocalDateTimeUtils.convertLocalDate());
            customerMapper.updateByExampleSelective(update, Example.builder(Customer.class).where(
                    WeekendSqls.<Customer>custom().andEqualTo(Customer::getId, customer.getId())
            ).build());
            //记录变更日志
            customerPersonChangeService.saveSaleChange(customer.getId(), Objects.nonNull(customer.getSalePersonId()) ? personService.getById(customer.getSalePersonId()) : null, newSalePerson, dto.getMemo());
        }
        //变更商务
        if (Objects.nonNull(dto.getBusPersonId())) {
            TsfPreconditions.checkArgument(!Objects.equals(dto.getBusPersonId(), customer.getBusPersonId()), new ServiceException("您本次没有更改商务人员"));
            Person newBusPerson = personService.getById(dto.getBusPersonId());
            Optional.ofNullable(newBusPerson).orElseThrow(() -> new ServiceException("您选择的商务人员不存在"));
            //修改客户最新商务人员
            Customer update = new Customer();
            update.setBusPersonId(newBusPerson.getId());
            customerMapper.updateByExampleSelective(update, Example.builder(Customer.class).where(
                    WeekendSqls.<Customer>custom().andEqualTo(Customer::getId, customer.getId())
            ).build());
            //记录变更日志
            customerPersonChangeService.saveBusChange(customer.getId(), Objects.nonNull(customer.getBusPersonId()) ? personService.getById(customer.getBusPersonId()) : null, newBusPerson, dto.getMemo());
        }
    }

    @Override
    public CustomerPersonVO getCustomerPerson(Long id) {
        List<String> selectFields = Lists.newArrayList("id", "name", "salePersonId", "busPersonId");
        Customer customer = customerMapper.selectOneByExample(Example.builder(Customer.class).where(TsfWeekendSqls.<Customer>custom().andEqualTo(false, Customer::getId, id)).select(selectFields.toArray(new String[selectFields.size()])).build());
        TsfPreconditions.checkArgument(Objects.nonNull(customer), new ServiceException("客户信息不存在"));
        CustomerPersonVO customerPersonVO = beanMapper.map(customer, CustomerPersonVO.class);
        Set<Long> personSet = Sets.newHashSet(customer.getBusPersonId(), customer.getSalePersonId());
        Map<Long, SimplePersonInfo> personMap = personService.findByIds(personSet);
        if (CollectionUtil.isNotEmpty(personMap)) {
            SimplePersonInfo simpleSalePersonInfo = personMap.get(customer.getSalePersonId());
            SimplePersonInfo simpleBusPersonInfo = personMap.get(customer.getBusPersonId());
            customerPersonVO.setSalePersonName(Objects.nonNull(simpleSalePersonInfo) ? simpleSalePersonInfo.getName() : null);
            customerPersonVO.setBusPersonName(Objects.nonNull(simpleBusPersonInfo) ? simpleBusPersonInfo.getName() : null);
        }
        return customerPersonVO;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void changeCustomerOrderDate(Long customerId, LocalDateTime orderDate) {
        Customer customer = super.getById(customerId);
        Optional.ofNullable(customer).orElseThrow(() -> new ServiceException("客户不存在"));

        Customer update = new Customer();
        //客户最近下单时间
        update.setEndOrderDate(orderDate);
        //客户首单时间
        if (Objects.isNull(customer.getFirstOrderDate())) {
            update.setFirstOrderDate(orderDate);
        }
        customerMapper.updateByExampleSelective(update, Example.builder(Customer.class).where(TsfWeekendSqls.<Customer>custom().andEqualTo(false, Customer::getId, customerId)).build());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Customer saveEmptyInfo() {
        Customer customer = new Customer();
        customer.setCode(createCustomerCode());
        //待完善资料
        CustomerStatusEnum nowStatus = CustomerStatusEnum.TYPE_0;
        customer.setStatusId(nowStatus.getCode());
        customerMapper.insertSelective(customer);

        statusHistoryService.saveHistory(DomainOprationEnum.CUSTOMER_ADD,
                customer.getId().toString(),Customer.class.getName(),
                nowStatus.getCode(),nowStatus.getName(),
                "客户自主注册");
        return customer;
    }

    @Override
    public CompanyVO companyInfo(Long id) {
        Customer customer = getById(id);
        if (Objects.nonNull(customer)) {
            CompanyVO companyVO = beanMapper.map(customer, CompanyVO.class);
            String[] address = StringUtils.removeSpecialSymbol(companyVO.getLinkAddress()).split(" ");
            if(address.length>=3){
                companyVO.setInvoiceProvince(address[0]);
                companyVO.setInvoiceCity(address[1]);
                companyVO.setInvoiceArea(address[2]);
                address[0]="";
                address[1]="";
                address[2]="";
                companyVO.setLinkAddress(String.join("",address));
            }
            // 待完善资料
            if(CustomerStatusEnum.TYPE_0.getCode().equals(companyVO.getStatusId())){
                companyVO.setAuditOpinion(statusHistoryService.findInfoByDomainAndNowStatus(companyVO.getId().toString(),Customer.class.getName(),companyVO.getStatusId()));
            }
            return companyVO;
        }
        return null;
    }

    @Override
    public BusinessLicenseVO businessLicenseOcr(Long id) {
        UploadFile uploadFile = uploadFileService.getById(id);
        if (Objects.isNull(uploadFile)) {
            return null;
        }
        BusinessLicenseVO blVO = null;
        try {
            //调用百度识别营业执照（随机调用一个）
            List<Map<String,String>> baiduInfos = baiduProperties.getApi();
            Map<String,String> baiduKeyInfo = baiduInfos.get(new Random().nextInt(baiduInfos.size()));
            HashMap<String, String> options = new HashMap<>();
            AipOcr client = new AipOcr(baiduKeyInfo.get("appId"), baiduKeyInfo.get("key"), baiduKeyInfo.get("secret"));
            String image = uploadFile.getPath().concat(uploadFile.getNname());
            JSONObject res = client.businessLicense(image, options);
            log.info("百度识别营业执照响应【{}】",res.toString());
            com.alibaba.fastjson.JSONObject json = com.alibaba.fastjson.JSONObject.parseObject(res.toString());
            if(json.containsKey("error_code")) {
                log.info("百度识别营业执照响应异常，响应内容：【{}】",res.toString());
                return null;
            }
            com.alibaba.fastjson.JSONObject comjson = json.getJSONObject("words_result");
            blVO = new BusinessLicenseVO();
            String socialNo = comjson.getJSONObject("社会信用代码").getObject("words", String.class);
            String legalPerson = comjson.getJSONObject("法人").getObject("words", String.class);
            String address = comjson.getJSONObject("地址").getObject("words", String.class);
            String name = comjson.getJSONObject("单位名称").getObject("words", String.class);
            blVO.setName("无".equals(name) ? "" : name.trim().replace("(","（").replace(")","）"));
            blVO.setSocialNo("无".equals(socialNo) ? "" : socialNo.trim());
            blVO.setLegalPerson("无".equals(legalPerson) ? "" : legalPerson.trim());
            blVO.setAddress("无".equals(address) ? "" : address.trim());

            if(StringUtils.isNotEmpty(blVO.getName())&&(
                    StringUtils.isEmpty(blVO.getSocialNo())
                    || blVO.getSocialNo().length() != 18
                    || StringUtils.isEmpty(blVO.getLegalPerson())
                    || StringUtils.isEmpty(blVO.getAddress()))
            ){
                Result<QichachaCompanyVO> qichachaCompanyVOResult = toolClient.detailByCompanyName(blVO.getName());
                if(qichachaCompanyVOResult.isSuccess() && Objects.nonNull(qichachaCompanyVOResult.getData())){
                    QichachaCompanyVO qichachaCompanyVO = qichachaCompanyVOResult.getData();
                    blVO.setSocialNo(qichachaCompanyVO.getCreditCode());
                    blVO.setLegalPerson(qichachaCompanyVO.getOperName());
                    blVO.setAddress(qichachaCompanyVO.getAddress());
                }
            }
        } catch (Exception e) {
            log.error("调用百度识别营业执照失败：", e);
        }
        return blVO;
    }

    @Override
    public Integer updateCompany(CompanyDTO dto) {
        Customer customer = super.getById(SecurityUtil.getCurrentCustomerId());
        TsfPreconditions.checkArgument(Objects.nonNull(customer), new ServiceException("公司信息不存在"));
        //历史状态
        CustomerStatusEnum oldStatus = CustomerStatusEnum.of(customer.getStatusId());
        //审核原因
        String reason = "";
        try {
            Integer result = 0;
            // 获取营业执照
            List<ClientFileVO> clientFileVOList = uploadFileService.findByFile(customer.getId().toString(),"customer","cus_business");
//            if(CollUtil.isEmpty(clientFileVOList)){
//                throw new ServiceException("请上传营业执照");
//            }
            customer.setTel(dto.getTel());//公司电话
            customer.setFax(dto.getFax());//公司传真
            customer.setCustomsCode(dto.getCustomsCode());//海关代码
            customer.setAddress(dto.getAddress());//公司地址
            // 不是已审核状态
            if(!Objects.equals(oldStatus,CustomerStatusEnum.TYPE_2)){
                customer.setName(dto.getName().replace("(","（").replace(")","）"));
                customer.setSocialNo(dto.getSocialNo());
                customer.setLegalPerson(dto.getLegalPerson());
                // 拼音
                customer.setPinyin(ChineseToPingYin.getPingYin(customer.getName()));
                try{
                    //验证公司名称和统一社会信用代码
                    Result<QichachaCompanyVO> qichachaCompanyVOResult = toolClient.detailByCompanyName(customer.getName());
                    if(qichachaCompanyVOResult.isSuccess() && Objects.nonNull(qichachaCompanyVOResult.getData())){
                        QichachaCompanyVO qichachaCompanyVO = qichachaCompanyVOResult.getData();
                        if(!customer.getSocialNo().equals(qichachaCompanyVO.getCreditCode())){
                            throw new ServiceException("公司名称与统一信用代码不匹配请检查");
                        }
                    }else{
                        //转入人工审核
                        reason = "未查询到公司的工商信息，需要人工审核。";
                    }
                }catch (Exception e){
                    //转入人工审核
                    reason = "未查询到公司的工商信息，需要人工审核。";
                }
                // 默认待审核状态
                CustomerStatusEnum nowStatus = CustomerStatusEnum.TYPE_1;
//                if(StringUtils.isEmpty(reason)){
//                    // 识别营业执照
//                    BusinessLicenseVO businessLicenseVO = businessLicenseOcr(clientFileVOList.get(0).getId());
//                    if(Objects.nonNull(businessLicenseVO)
//                            && customer.getName().equals(businessLicenseVO.getName())
//                            && customer.getSocialNo().equals(businessLicenseVO.getSocialNo())
//                    ){
//                        // 已审核
//                        nowStatus = CustomerStatusEnum.TYPE_2;
//                        reason = "工商接口，营业执照识别，数据一致，系统自动审核通过。";
//                    }else{
//                        reason = "工商信息与营业执照识别数据不一致，需要人工审核。";
//                    }
//                }
                // 修改客户状态
                customer.setStatusId(nowStatus.getCode());
                statusHistoryService.saveHistory(DomainOprationEnum.CUSTOMER_ADD,
                        customer.getId().toString(),Customer.class.getName(),
                        oldStatus.getCode(),oldStatus.getName(),
                        nowStatus.getCode(),nowStatus.getName(),reason);
                result = Objects.equals(nowStatus,CustomerStatusEnum.TYPE_2)?1:2;
            }
            // 税务登记证
            if(StringUtils.isEmpty(customer.getTaxpayerNo())){
                customer.setTaxpayerNo(customer.getSocialNo());
            }

            // 修改客户信息
            super.updateById(customer);
            //刷新公司缓存数据
            refreshCacheCompany(customer);

            //通知类放在后面，以防报错也发送了通知
            if(!Objects.equals(oldStatus,CustomerStatusEnum.TYPE_2)) {
                CustomerStatusEnum nowStatus = CustomerStatusEnum.of(customer.getStatusId());
                // 待审核 钉钉通知审核
                if(Objects.equals(nowStatus,CustomerStatusEnum.TYPE_1)){
                    LoginVO loginVO = SecurityUtil.getCurrent();
                    DingTalkNoticeUtil.send2DingDingBiz("客户审核",String.format("【%s】%s【%s】",customer.getName(),reason,Objects.nonNull(loginVO) ? loginVO.getPhone() : ""),ddRemindProperties.getDingding(),profiles);
                }
                //由待审核改成已审核
                Person person = personService.getPhoneByCustomerId(customer.getId());
                if(Objects.equals(nowStatus,CustomerStatusEnum.TYPE_2)) {
                    //发送短信通知
                    LinkedHashMap<String,String> paramsMap = new LinkedHashMap<>();
                    SmsNoticeMessageDTO smsNoticeMessageDTO = new SmsNoticeMessageDTO();
                    smsNoticeMessageDTO.setMessageNodeEnum(MessageNodeEnum.CUSTOMER_APROVED);
                    smsNoticeMessageDTO.setPhoneNo(Objects.nonNull(person) ? person.getPhone() : "");
                    smsNoticeMessageDTO.setParams(paramsMap);
                    shortMessageService.sendNoticeMessage(smsNoticeMessageDTO);

                    //发送微信公众号消息
                    WxNoticeMessageDTO wxNoticeMessageDTO = new WxNoticeMessageDTO();
                    wxNoticeMessageDTO.setWxgzhOpenid(Objects.nonNull(person) ? person.getWxgzhOpenid() : "");
                    wxNoticeMessageDTO.setWxMessageDefineTemplate(WxMessageDefineTemplate.CUSTOMER_APROVED);
                    wxNoticeMessageDTO.setIsNavToMiniprogram(Boolean.TRUE);
                    wxNoticeMessageDTO.setMiniprogram(new WxMiniProgram("/pages/company/info"));
                    LinkedHashMap<String, WxNoticeAttr> params = new LinkedHashMap<>();
                    params.put("first",new WxNoticeAttr("尊敬的用户，您提交的资料已通过审核","#04BE02"));
                    params.put("keyword1",new WxNoticeAttr(person.getPhone(),"#9C9C9C"));
                    params.put("keyword2",new WxNoticeAttr(customer.getName(),"#9C9C9C"));
                    params.put("keyword3",new WxNoticeAttr("资料完善","#9C9C9C"));
                    params.put("remark",new WxNoticeAttr("您提交的资料已通过审核，请尽快登录我司官网签约好协议后即可下单。"));
                    wxNoticeMessageDTO.setParams(params);
                    wxMessageService.sendWxNotice(wxNoticeMessageDTO);
                }
            }

            return result;
        }catch (ServiceException e){
            throw e;
        }catch (DuplicateKeyException e) {
            if (e.getMessage().contains("UK_customer_code")) {
                throw new ServiceException("公司代码已经存在请修改");
            } else if (e.getMessage().contains("UK_customer_name")) {
                throw new ServiceException("当前公司名称已经被注册");
            } else {
                throw new ServiceException("保存失败，请检查数据是否填写正确");
            }
        }
    }

    @Override
    public CompanyVO refreshCacheCompany(Long id) {
        return refreshCacheCompany(super.getById(id));
    }

    @Override
    public CompanyVO refreshCacheCompany(Customer customer) {
        CompanyVO company = beanMapper.map(customer,CompanyVO.class);
        redisUtils.set(LoginConstant.COMPANY.concat(company.getId().toString()),company,Long.valueOf(1),TimeUnit.DAYS);
        return company;
    }

    @Override
    public CompanyVO getCacheCompany(Long id) {
        Object object = redisUtils.get(LoginConstant.COMPANY.concat(id.toString()));
        if(Objects.nonNull(object)){
            return beanMapper.map(object,CompanyVO.class);
        }
        return refreshCacheCompany(id);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveCustomerInvoiceInfo(CustomerInvoiceInfoDTO dto) {
        Long customerId = SecurityUtil.getCurrentCustomerId();
        if(Objects.isNull(customerId) || 0L == customerId) {
            throw new ServiceException(ResultCodeEnum.CUSTOMER_NO_EXISTS_ERROR);
        }
        Customer customer = super.getById(customerId);
        if(Objects.isNull(customer)) {
            throw new ServiceException(ResultCodeEnum.CUSTOMER_NO_EXISTS_ERROR);
        }
        customer.setTaxpayerNo(dto.getTaxpayerNo());
        customer.setInvoiceBankName(dto.getInvoiceBankName());
        customer.setInvoiceBankAccount(dto.getInvoiceBankAccount());
        customer.setInvoiceBankTel(dto.getInvoiceBankTel());
        customer.setInvoiceBankAddress(dto.getInvoiceBankAddress());
        customer.setInvoiceMemo(dto.getInvoiceMemo());
        customer.setLinkPerson(dto.getLinkPerson());
        customer.setLinkTel(dto.getLinkTel());
        customer.setLinkAddress(String.format("%s %s %s %s",
                StringUtils.removeSpecialSymbol(dto.getInvoiceProvince()),
                StringUtils.removeSpecialSymbol(dto.getInvoiceCity()),
                StringUtils.removeSpecialSymbol(dto.getInvoiceArea()),
                StringUtils.removeSpecialSymbol(dto.getLinkAddress())));
        super.updateById(customer);
        // 刷新客户资料
        refreshCacheCompany(customer);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void approvingCustomer(TaskDTO dto) {
        Customer customer =  commonService.changeDocumentStatus(dto);
        //刷新缓存
        refreshCacheCompany(customer);
        //人工审核发送微信通知告知客户
        //发送微信通知
        Person person = personService.getPhoneByCustomerId(customer.getId());
        if(Objects.isNull(person)) {
            return;
        }
        //发送短信通知客户
        if(Objects.equals(dto.getNewStatusCode(),CustomerStatusEnum.TYPE_2.getCode())){
            LinkedHashMap<String,String> paramsMap = new LinkedHashMap<>();
            SmsNoticeMessageDTO smsNoticeMessageDTO = new SmsNoticeMessageDTO();
            smsNoticeMessageDTO.setMessageNodeEnum(MessageNodeEnum.CUSTOMER_APROVED);
            smsNoticeMessageDTO.setPhoneNo(Objects.nonNull(person) ? person.getPhone() : "");
            smsNoticeMessageDTO.setParams(paramsMap);
            shortMessageService.sendNoticeMessage(smsNoticeMessageDTO);
        } else if (Objects.equals(dto.getNewStatusCode(),CustomerStatusEnum.TYPE_0.getCode())) {
            LinkedHashMap<String,String> paramsMap = new LinkedHashMap<>();
            SmsNoticeMessageDTO smsNoticeMessageDTO = new SmsNoticeMessageDTO();
            smsNoticeMessageDTO.setMessageNodeEnum(MessageNodeEnum.CUSTOMER_REJECT);
            smsNoticeMessageDTO.setPhoneNo(Objects.nonNull(person) ? person.getPhone() : "");
            smsNoticeMessageDTO.setParams(paramsMap);
            shortMessageService.sendNoticeMessage(smsNoticeMessageDTO);
        }
        WxNoticeMessageDTO wxNoticeMessageDTO = new WxNoticeMessageDTO();
        wxNoticeMessageDTO.setWxgzhOpenid(Objects.nonNull(person) ? person.getWxgzhOpenid() : "");
        wxNoticeMessageDTO.setWxMessageDefineTemplate(WxMessageDefineTemplate.CUSTOMER_APROVED);
        wxNoticeMessageDTO.setIsNavToMiniprogram(Boolean.TRUE);
        wxNoticeMessageDTO.setMiniprogram(new WxMiniProgram("/pages/company/info"));
        LinkedHashMap<String, WxNoticeAttr> params = new LinkedHashMap<>();
        if(Objects.equals(dto.getNewStatusCode(),CustomerStatusEnum.TYPE_2.getCode())) {
            params.put("first",new WxNoticeAttr("尊敬的用户，您提交的资料已通过审核","#04BE02"));
            params.put("keyword1",new WxNoticeAttr(person.getPhone(),"#9C9C9C"));
            params.put("keyword2",new WxNoticeAttr(customer.getName(),"#9C9C9C"));
            params.put("keyword3",new WxNoticeAttr("资料完善","#9C9C9C"));
            params.put("remark",new WxNoticeAttr("您提交的资料已通过审核，签约协议后将可以下单"));
        } else if (Objects.equals(dto.getNewStatusCode(),CustomerStatusEnum.TYPE_0.getCode())) {
            params.put("first",new WxNoticeAttr("尊敬的用户，您提交的资料审核不通过"));
            params.put("keyword1",new WxNoticeAttr(person.getPhone(),"#9C9C9C"));
            params.put("keyword2",new WxNoticeAttr(customer.getName(),"#9C9C9C"));
            params.put("keyword3",new WxNoticeAttr(StringUtils.null2EmptyWithTrim(dto.getMemo()),"#9C9C9C"));
            params.put("remark",new WxNoticeAttr("您提交的资料未通过审核，请您修改资料信息后等待审核"));
        }
        wxNoticeMessageDTO.setParams(params);
        wxMessageService.sendWxNotice(wxNoticeMessageDTO);
    }

    @Override
    public ClientFinanceInfoVO getCompanyFinance() {
        Long customerId = SecurityUtil.getCurrentCustomerId();
        //客户余额
        BigDecimal customerBalance = transactionFlowService.getCustomerBalance(customerId);
        //优惠券余额
        BigDecimal couponNumber = BigDecimal.ZERO;
        Customer customer = super.getById(customerId);
        //客户可用货款额度
        BigDecimal goodsQuota = customer.getGoodsQuota();
        //收款未核销金额
        BigDecimal receivablesVal = receiptAccountService.obtainCustomerReceipts(customerId);
        //获取客户货款占用额度（应收货款未核销金额）
        BigDecimal goodsCostTotal = impOrderCostService.customerGoodsTotal(customerId);
        //收款未核销金额 - 应收货款未核销金额
        BigDecimal goodsOccupyQuota = receivablesVal.subtract(goodsCostTotal).setScale(2,BigDecimal.ROUND_HALF_UP);
        if(goodsOccupyQuota.compareTo(BigDecimal.ZERO)==-1) { //出现负数
            goodsQuota = goodsQuota.add(goodsOccupyQuota).setScale(2,BigDecimal.ROUND_HALF_UP);
        }
        //客户可用税款额度
        BigDecimal taxQuota = customer.getTaxQuota();
        //收款未核销金额 - 应收税杂费未核销金额 - 本订单费用
        BigDecimal taxOccupyQuota = receivablesVal.subtract(taxQuota).setScale(2,BigDecimal.ROUND_HALF_UP);
        if(taxOccupyQuota.compareTo(BigDecimal.ZERO)==-1){ //出现负数
            taxQuota = taxQuota.add(taxOccupyQuota).setScale(2,BigDecimal.ROUND_HALF_UP);
        }
        BigDecimal totalArrearsVal  = impOrderCostService.customerArrearsTotal(customerId);
        ClientFinanceInfoVO clientFinanceInfoVO = new ClientFinanceInfoVO();
        clientFinanceInfoVO.setBalance(customerBalance);
        clientFinanceInfoVO.setCouponNumber(couponNumber);
        clientFinanceInfoVO.setGoodsAmount(goodsQuota);
        clientFinanceInfoVO.setTaxAmount(taxQuota);
        clientFinanceInfoVO.setTotalArrearsVal(totalArrearsVal);
        return clientFinanceInfoVO;
    }

    @Override
    public ClientCustomerGradeVO companyPerfectShow() {
        Long customerId = SecurityUtil.getCurrentCustomerId();
        Long personId = SecurityUtil.getCurrentPersonId();
        Customer customer = super.getById(customerId);
        Person person = personService.getById(personId);
        ClientCustomerGradeVO clientCustomerGradeVO = new ClientCustomerGradeVO();
        // 计算资料完善度
        int perfectGrade = CompanyUtil.getInstance().calCompanyGrade(customer,person);
        clientCustomerGradeVO.setPerfectGrade(perfectGrade);
        // 登录日志
        LogLogin lastLogin = logLoginService.personLastLogin(personId,DeviceUtil.getPlatform().getCode());
        clientCustomerGradeVO.setLastLoginTime(Objects.nonNull(lastLogin) ? lastLogin.getDateCreated() : null);
        // 安全度级别
        String accountSafeLevel = CompanyUtil.getInstance().accountSafeLevel(person);
        clientCustomerGradeVO.setAccountSafeLevel(accountSafeLevel);
        // 绑定微信登录
        //clientCustomerGradeVO.setBindWeixin(StringUtils.isNotEmpty(person.getWxgzhOpenid()));
        //改成绑定微信登录
        clientCustomerGradeVO.setBindWeixin(loginService.checkUserBindWxLogin(personId));
        // 绑定手机号
        clientCustomerGradeVO.setBindPhone(StringUtils.isNotEmpty(person.getPhone()));
        // 绑定邮箱
        clientCustomerGradeVO.setBindMail(StringUtils.isNotEmpty(person.getMail()));
        // 设置密码
        clientCustomerGradeVO.setSetPassword(StringUtils.isNotEmpty(person.getPassWord()));
        // 客户信息
        clientCustomerGradeVO.setCode(customer.getCode());
        clientCustomerGradeVO.setName(customer.getName());

        clientCustomerGradeVO.setStatusId(customer.getStatusId());
        // 待完善资料
        if(CustomerStatusEnum.TYPE_0.getCode().equals(customer.getStatusId())){
            clientCustomerGradeVO.setAuditOpinion(statusHistoryService.findInfoByDomainAndNowStatus(customer.getId().toString(),Customer.class.getName(),customer.getStatusId()));
        }
        return clientCustomerGradeVO;
    }

    @Override
    public List<SimpleBusinessVO> vagueSimpleBusinessQuery(String name) {
//        if(StringUtils.isEmpty(name)){
//            return Lists.newArrayList();
//        }
//        Result<List<SimpleBusinessVO>> result = toolClient.vagueQuery(name);
//        if(result.isSuccess()){
//            return result.getData();
//        }
        return Lists.newArrayList();
    }

    @Override
    public CustomerSimpleVO findByCustomerId(Long customerId) {
        return customerMapper.findByCustomerId(customerId);
    }

    @Override
    public List<CustomerSimpleVO> allAuditCustomer() {
        List<Customer> customers =  customerMapper.selectByExample(Example.builder(Customer.class).where(TsfWeekendSqls.<Customer>custom()
                .andEqualTo(false,Customer::getStatusId,"audited")).select("id","code","name","socialNo").build());
        return beanMapper.mapAsList(customers,CustomerSimpleVO.class);
    }

    @Override
    public Map<Long, CustomerSimpleVO> obtainCustomerSimples(Set<Long> customerIds) {
        Map<Long, CustomerSimpleVO> map = new LinkedMap<>();
        if(CollUtil.isNotEmpty(customerIds)){
            for(Long customerId : customerIds){
                String key = "CUSTOMER:"+customerId;
                Object obj = redisUtils.get(key);
                if(Objects.nonNull(obj)){
                    map.put(customerId,(CustomerSimpleVO)obj);
                }else{
                    CustomerSimpleVO vo = findByCustomerId(customerId);
                    if(Objects.nonNull(vo)){
                        map.put(customerId,vo);
                        redisUtils.set(key,vo,Long.valueOf(30), TimeUnit.DAYS);
                    }
                }
            }
        }
        return map;
    }

    @Override
    public CheckCompanyResultVO checkCompanyName(String name) {
        // 查询当前用户客户信息
        Customer myCustomer = super.getById(SecurityUtil.getCurrentCustomerId());
        name = StringUtils.removeSpecialSymbol(name).replace("(", "（").replace(")", "）");
        // 修改的名称和当前客户名称一致
        if(Objects.equals(myCustomer.getName(),name)){
            return new CheckCompanyResultVO(0,null);
        }
        Customer newCustomer = findByName(name);
        // 修改的名称未被占用
        if(Objects.isNull(newCustomer)){
            return new CheckCompanyResultVO(0,null);
        }
        // 如果新客户未被绑定账号说明是后端销售备案的，允许客户进行绑定
        Map<Long, CustomerLoginInfoVO> loginInfoVOMap = loginService.allCustomerLoginInfo();
        if(Objects.isNull(loginInfoVOMap.get(newCustomer.getId()))){
            return new CheckCompanyResultVO(1,newCustomer.getId());
        }
        return new CheckCompanyResultVO(2,null);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long claimCompany(Long ncustomerId) {
        // 查询当前用户客户信息
        Customer myCustomer = super.getById(SecurityUtil.getCurrentCustomerId());
        if(Objects.equals(CustomerStatusEnum.of(myCustomer.getStatusId()),CustomerStatusEnum.TYPE_2)){
            throw new ServiceException("您的公司资料已审核通过，请刷新页面查看");
        }
        Customer newCustomer = super.getById(ncustomerId);
        TsfPreconditions.checkArgument(Objects.nonNull(newCustomer),new ServiceException("认领的公司不存在"));
        // 查询认领的公司是否被注册
        Map<Long, CustomerLoginInfoVO> loginInfoVOMap = loginService.allCustomerLoginInfo();
        TsfPreconditions.checkArgument(Objects.isNull(loginInfoVOMap.get(newCustomer.getId())),new ServiceException("当前公司已被认领"));
        // 将新公司绑定到当前账户下
        customerPersonService.newBindCustomerPerson(SecurityUtil.getCurrentPersonId(),myCustomer.getId(),newCustomer.getId());
        // 修改人员客户ID
        personService.updatePersonCustomerId(SecurityUtil.getCurrentPersonId(),newCustomer.getId());
        // 刷新客户缓存数据
        refreshCacheCompany(newCustomer);
        // 刷新用户登录数据
        LoginVO loginVO = SecurityUtil.getCurrent();
        loginVO.setCustomerId(newCustomer.getId());
        loginVO.setCustomerName(newCustomer.getName());
        //更新用户缓存数据
        stringRedisUtils.set(LoginConstant.AUTH.concat(loginVO.getPersonId().toString()), com.alibaba.fastjson.JSONObject.toJSONString(loginVO));
        return newCustomer.getId();
    }
}
